﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using System.ServiceModel.Description;
using CrmClient.Linq;

namespace PerfomanceTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Operation \tMyCrmClient\t\tSdkCrmClient");
            var orgConfigInfo = ServiceConfigurationFactory.CreateConfiguration<IOrganizationService>(new Uri("http://alpes/kacit/XrmServices/2011/Organization.svc"));
            using (var _serviceProxy = new OrganizationServiceProxy(orgConfigInfo, new ClientCredentials()))
            {
                _serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
                using (context srv = new context((IOrganizationService)_serviceProxy))
                using (var client = new OrgCrmClient())
                {
                    //initial
                    var users = srv.AccountSet.ToList();
                    client.Query<account>().ToList();
                    //Metrics
                    GetMetric("Query     ", () => srv.AccountSet, () => client.Query<account>());
                    GetMetric("Select    ", () => srv.AccountSet.Select(i => new { i.Id, i.Name }), () => client.Query<account>().CrmSelect(i => new { i.Id, i.Name }));
                    GetMetric("Order     ", () => srv.AccountSet.OrderBy(i => i.Name).ThenBy(i => i.Id), () => client.Query<account>().CrmOrderBy(i => i.Name).CrmOrderBy(i => i.Id));
                    GetMetric("Where     ", () => srv.AccountSet.Where(i => i.Id == users[0].Id), () => client.Query<account>().CrmWhere(i => i.Id == users[0].Id));
                    GetMetric("WhereIn   ",
                        () => srv.AccountSet.Where(i => users.Take(10).Select(u => u.Id).ToArray().Contains(i.Id)),
                        () => client.Query<account>().CrmWhere(i => users.Take(10).Select(u => u.Id).ToArray().Contains(i.Id)));
                    GetMetric("%Like%    ", () => srv.AccountSet.Where(i => i.Name.Contains("CRM")), () => client.Query<account>().CrmWhere(i => i.Name.Contains("CRM")));
                    GetMetric("%Like     ", () => srv.AccountSet.Where(i => i.Name.EndsWith("CRM")), () => client.Query<account>().CrmWhere(i => i.Name.EndsWith("CRM")));
                    GetMetric("Like%     ", () => srv.AccountSet.Where(i => i.Name.StartsWith("CRM")), () => client.Query<account>().CrmWhere(i => i.Name.StartsWith("CRM")));
                    GetMetric("Join      ",
                        () => srv.AccountSet.Join(srv.AccountSet, s => s.ParentAccountId.Id, d => d.Id, (s, d) => new { s.Id, s.Name, ParentId = d.Id, ParentName = d.Name }),
                        () => client.Query<account>().CrmJoin(client.Query<account>(), s => s.ParentAccountId.Id, d => d.Id, (s, d) => new { s.Id, s.Name, ParentId = d.Id, ParentName = d.Name }));

                    var parentAccountId = users.Where(u => u.ParentAccountId != null).First().Id;
                    GetMetric("JoinFilter",
                        () => srv.AccountSet.Join(srv.AccountSet, s => s.ParentAccountId.Id, d => d.Id, (s, d) => new { s.Id, s.Name, ParentId = d.Id, ParentName = d.Name }).Where(i => i.ParentId == parentAccountId),
                        () => client.Query<account>().CrmJoin(client.Query<account>().CrmWhere(i => i.Id == parentAccountId), s => s.ParentAccountId.Id, d => d.Id, (s, d) => new { s.Id, s.Name, ParentId = d.Id, ParentName = d.Name }));

                    GetMetric<Account, account>("NoLock    ", () => { throw new NotSupportedException(); }, () => client.Query<account>().CrmNoLock());
                    GetMetric("Distinct  ", () => srv.AccountSet.Distinct(), () => client.Query<account>().CrmDistinct());
                }
            }
            Console.WriteLine("Done");
            Console.ReadLine();
        }

        static void GetMetric<T1, T2>(string name, Func<IEnumerable<T1>> mssdkcrmclient, Func<IEnumerable<T2>> mycrmclient)
        {
            string sdkcrmclienttime;
            List<T1> mssdkcrmclientItems = Iterate(mssdkcrmclient, out sdkcrmclienttime);
            string mycrmclienttime;
            List<T2> mycrmclientItems = Iterate(mycrmclient, out mycrmclienttime);
            Console.Write(name + "\t" + mycrmclienttime + "\t" + sdkcrmclienttime);
            if (mycrmclientItems.Count > 0 && mssdkcrmclientItems.Count > 0 && !CollectionsAreEquals(mycrmclientItems, mssdkcrmclientItems))
                Console.Write("\t not eq!!!");
            Console.WriteLine(string.Empty);
        }

        static List<T> Iterate<T>(Func<IEnumerable<T>> mssdkcrmclient, out string time)
        {
            var res = new List<T>();
            try
            {
                var startsdk = DateTime.Now;
                for (int i = 0; i < 10; i++)
                    res.AddRange(mssdkcrmclient());
                time = (DateTime.Now - startsdk).ToString();
            }
            catch (NotSupportedException ex) { time = "not supported"; }
            catch (Exception ex) { time = "error"; }
            return res;
        }

        static bool CollectionsAreEquals<T1, T2>(List<T1> first, List<T2> second)
        {
            if (first.Count != second.Count)
                return false;
            for (int i = 0; i < first.Count; i++)
                if (!ItemsAreEqualsById(first[i], second[i]))
                    return false;
            return true;
        }
        static bool ItemsAreEqualsById<T1, T2>(T1 first, T2 second)
        {
            var firstId = (Guid)typeof(T1).GetProperty("Id").GetValue(first, null);
            var secondId = (Guid)typeof(T2).GetProperty("Id").GetValue(second, null);
            return firstId == secondId;
        }
    }
}
    

